package sma.iss.calc;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import sma.iss.Position;
import sma.iss.util.AngleUtil;
import sma.nasa.ConstraintsChecker;

/**
 * calculate the theoritical power
 * 
 * @author smarsoll
 * 
 */
public class CalcPower {
	// public class CalcPower implements Calculator {

	/** Logger for this class. */
	private final static Logger LOGGER = LoggerFactory.getLogger(CalcPower.class);

	/** official scoring is with MAX_ROTATION_PER_REV = 80.0 */
	private static final double MAX_ROTATION_PER_REV = 80.0 - 5.0;
	/** ? multiply by 1.5 because it is the final sum that is important */
	// private static final double MAX_ROTATION_PER_SEC = MAX_ROTATION_PER_REV / (92.0 * 60.0);

	public static final double DIVISOR_FOR_NEG_REV = 8.0;

	/*
	 * output is:
	 * 
	 * The cosine of the angle between the blanket normal and the vector to the sun for each SAW (8 values).
	 * 
	 * The shadow fraction of each string (8 SAWs x 2 blankets x 41 strings = 656 values).
	 * 
	 * The shadow fraction of each longeron (8 SAWs x 4 longerons = 32 values).
	 */

	public final double calculate(double[] output, Position previousPos, Position position,
			int[] currentDangerCounterRev, double[] previousRevBga, double deltaSeconde) {
		double resultSum = 0.0;

		// Power = (1371.3 watts/meter2) * cos(theta) * (0.1) * (2.56 meter2) * (ShadowFactor)
		// int maxIndex = 0;

		for (int iSaw = 0; iSaw < 8; iSaw++) {
			double cosNormal = output[iSaw];
			double resultSaw = 0.0;
			double efficiency = 0.1;
			if (cosNormal < 0) {
				// just to minimize shadowed (returned SAW)
				efficiency = 0.01;
			}

			for (int iString = 0; iString < 656; iString++) {
				double shadowFraction = output[8 + iString];
				// maxIndex = 8 + iString;
				double shadowFactor = Math.max(0.0, 1.0 - 5.0 * shadowFraction);
				double power = 1371.3 * cosNormal * efficiency * (2.56) * (shadowFactor);
				// LOGGER.info("power={}", power);
				resultSaw += power;
			}

			double minPower = ConstraintsChecker.MIN_POWER_REQ[iSaw];
			if (resultSaw < minPower) {
				// give importance to lower value
				// LOGGER.debug("resultSaw raw {} = {}", iSaw, resultSaw);
				resultSaw = 4.0 * resultSaw - 3.0 * minPower;
			}
			resultSum += resultSaw;
			// LOGGER.debug("output[iResult]={}", output[iResult]);
		}
		// consider R is the maximum of the total amount of rotation applied to each BGA over the entire orbit
		double maxShift = 0.0;
		// nb minutes from previous position:
		int multiplyDanger = 1;
		if (previousPos != null) {
			multiplyDanger = previousPos.getDelatMinuteToPos(position);
			for (int iBga = 0; iBga < 8; iBga++) {
				double shift = Math.abs(AngleUtil.getShift(previousPos.getAngle(iBga + 2), position.getAngle(iBga + 2)));
				if (position.minute < 0) {
					shift /= DIVISOR_FOR_NEG_REV;
				}
				shift += previousRevBga[iBga];
				if (shift > maxShift) {
					maxShift = shift;
				}
			}
		}
		// official scoring is with divisor = 300.0;
		final double divisor = 280.0;
		double exposant = (MAX_ROTATION_PER_REV - maxShift) / divisor;
		if (exposant > 0.0) {
			// minimise multiplier effect
			exposant = exposant / 4.0;
		}
		double malusRotation = Math.pow(2.0, exposant);

		// Longerons Danger count
		// LOGGER.info("{}", maxIndex);
		// int[] nbDangerPrevious = new int[8];
		// if (dangerCounterPrevious != null) {
		// double interpolator = 19.0 / dangerCounterPrevious.size();
		//
		// }
		// starting at 664: 32 longeron shadow fractions (4 values per BGA grouped together, then the groups are in
		// standard order).
		double dangerCount = 0;

		for (int iBga = 0; iBga < 8; iBga++) {
			int nbShadowed = 0;
			for (int ilong = 0; ilong < 4; ilong++) {
				double shadowFraction = output[664 + iBga * 4 + ilong];
				// LOGGER.info("{} {} {}", iBga, ilong, shadowFraction);
				// A longeron is considered shadowed if at least 10% of the length of the longeron is shadowed
				if (shadowFraction > 0.1) {
					nbShadowed++;
				}
			}
			// LOGGER.info("{} {} {}", nbShadowed);
			// If the mast has an odd number of longerons (1 or 3) shadowed, then the counter is incremented.
			if (nbShadowed == 1 || nbShadowed == 3) {
				// for future calculation:
				position.dangerCounter[iBga] = 1;
				// dangerCount++;
				// if (dangerCounterPrevious[iBga] > 10.0) {
				// // LOGGER.info("Dangerous for iBga={}", iBga);
				// dangerCount++;
				// if (dangerCounterPrevious[iBga] > 13.0) {
				// dangerCount++;
				// if (dangerCounterPrevious[iBga] > 18.0) {
				// // LOGGER.warn("Dangerous for iBga={}, counter={}", iBga, dangerCounterPrevious[iBga]);
				// dangerCount++;
				// }
				// }
				// }
			} else {
				position.dangerCounter[iBga] = -1;
			}
//			double cumulatedDanger = dangerCounterPrevious[iBga] + position.dangerCounter[iBga];
			double cumulatedDanger = currentDangerCounterRev[iBga] + position.dangerCounter[iBga] * multiplyDanger;

			if (cumulatedDanger < 15.0) {
				cumulatedDanger = 0.0;
			}
			dangerCount += cumulatedDanger;
		}
		// was 0.03, now 0.02
		double malusDanger = Math.pow(2.0, -dangerCount * 0.02);
		double finalScore = resultSum * malusRotation * malusDanger;
		// if (dangerCount >= 4) {
		// // LOGGER.info("" + dangerCount);
		// LOGGER.info("power sum={}, maxShift={}, malusRotation={}, malusDanger={}   =>{}", resultSum, maxShift,
		// malusRotation,
		// malusDanger, finalScore);
		// }
		return finalScore;
	}

}
